home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PsL Monthly 1993 December
/
PSL Monthly Shareware CD-ROM (December 1993).iso
/
prgmming
/
dos
/
c
/
cpptask.exe
/
TSKASM.ASM
< prev
next >
Wrap
Assembly Source File
|
1991-07-26
|
7KB
|
357 lines
;
; CTask - Scheduler and miscellaneous utilities
;
; Public Domain Software written by
; Thomas Wagner
; Patschkauer Weg 31
; D-1000 Berlin 33
; West Germany
;
IFDEF at
.186
ENDIF
name tskasm
.model large
;
public _asm_schedule
public _asm_c_schedule
public scheduler
public _sched_int
;
public _tsk_dis_int
public _tsk_ena_int
public _tsk_flags
public _tsk_nop
;
;
include tsk.mac
;
INT_FLAG = 2h ; Int enable flag in upper byte of flag reg
r_flags = 24 ; Offset of flag register on task stack
;
extrn _tsk_current: dword
extrn _tsk_eligible: dword
extrn _tsk_preempt: byte
extrn _tsk_pretick: byte
extrn _tsk_var_prior: byte
;
.data
;
in_sched db 0
;
.code
;
_dgroup dw seg dgroup
;
;------------------------------------------------------------------------
;
; enq Enqueue tcb in queue. For local use only.
; entry: es:di = tcb to enqueue
; exit: -
; uses: ax, cx, dx, bp, di
;
enq macro
;
lds bx,es:queue[di] ; queue head pointer
mov ax,ds
or ax,bx
jz enq_end ; nothing left to do if queue null
mov dx,es:prior[di] ; load priority of task
enq_l:
mov cx,bx ; save last ptr
mov bp,ds
lds bx,next[bx] ; load next
mov ax,ds
or ax,bx ; end of chain?
jz enq_found ; then insert
cmp dx,prior[bx] ; compare priority
jbe enq_l ; loop if tasks prior less or equal
;
enq_found:
mov word ptr es:next[di],bx ; set tasks next pointer
mov word ptr es:next+2[di],ds
mov bx,cx ; last pointer
mov ds,bp
mov word ptr next[bx],di ; last->next = task
mov word ptr next+2[bx],es
enq_end:
mov ds,_dgroup
;
endm
;
;
; upd_prior: Update priority of tasks in eligible queue.
; Only activated if tsk_var_prior is nonzero.
;
; NOTE: This loop is not protected by interrupt disable.
; Since it does not modify the queue itself, there
; is no danger of race conditions.
;
upd_prior macro
;
les di,_tsk_eligible
pinc_loop:
mov ax,es
or ax,di ; end of chain?
jz updp_end
inc es:prior[di]
jnz pinc_nxt
dec es:prior[di]
pinc_nxt:
les di,es:next[di]
jmp pinc_loop
;
updp_end:
;
endm
;
;
; The scheduler. Note that this routine is entered with the stack
; set up as for an interrupt handler.
;
scheduler proc far
;
cli ; better safe than sorry
push ds
mov ds,_dgroup
cmp in_sched,0 ; already in the scheduler?
je sched_ok ; continue if not
pop ds ; else return immediately
iret
;
sched_ok:
inc in_sched
pop ds
; sti ; we can now safely enable interrupts
IFNDEF at
push ax
push cx
push dx
push bx
push sp
push bp
push si
push di
ELSE
pusha
ENDIF
push ds
push es
;
mov ds,_dgroup ; establish addressing of our vars
;
cmp _tsk_var_prior,0
je no_var_pri
upd_prior ; update priority
;
no_var_pri:
cli ; the following is critical
;
les di,_tsk_current ; get current tcb
mov ax,es ; check if NULL (current task killed)
or ax,di
jz no_current
;
mov word ptr es:tcbstack[di],sp ; store stack pointer & seg
mov word ptr es:tcbstack+2[di],ss
;
cmp es:state[di],ST_RUNNING
jne not_eligible
mov es:state[di],ST_ELIGIBLE
not_eligible:
;
enq ; Enqueue current task
;
no_current:
mov _tsk_pretick,0 ; No preemption tick
and _tsk_preempt,1 ; Turn off temp preempt flag
;
wait_elig:
cli
les di,_tsk_eligible
;
; If eligible queue empty, enter waiting loop
;
mov ax,es
or ax,di ; is the eligible queue empty?
jnz not_empty ; jump if not
sti ; enable interrupts
nop
nop
jmp wait_elig
;
; Eligible queue not empty, activate first eligible task.
;
not_empty:
mov ax,word ptr es:next[di] ; load next pointer
mov word ptr _tsk_eligible,ax ; remove from queue
mov ax,word ptr es:next+2[di]
mov word ptr _tsk_eligible+2,ax
;
mov word ptr _tsk_current,di ; set tcb into current
mov word ptr _tsk_current+2,es
mov ax,es:iniprior[di] ; reset current tasks priority
mov es:prior[di],ax
;
mov in_sched,0 ; reset scheduler active flag
;
lds si,es:tcbstack[di] ; load stack
or byte ptr r_flags+1[si],INT_FLAG ; enable interrupts
mov es:state[di],ST_RUNNING ; set task state
mov cx,ds ; switch stack
mov ss,cx
mov sp,si
pop es ; restore all registers
pop ds
IFNDEF at
pop di
pop si
pop bp
pop bx ; don't pop SP
pop bx
pop dx
pop cx
pop ax
ELSE
popa
ENDIF
iret
;
scheduler endp
;
;
;--------------------------------------------------------------------------
;
;
; _sched_int
;
; Is the scheduler entry for interrupt handlers.
; It checks if preemption is allowed, returning if not.
; The stack is assumed to be set up as on interrupt entry.
;
_sched_int proc far
;
push ds
push bx
mov ds,_dgroup
cmp _tsk_preempt,0 ; preempt flags 0?
jne no_sched ; no scheduling if set
lds bx,_tsk_current ; current running task
test flags[bx],F_CRIT ; preemption allowed for this task?
jnz no_sched ; no scheduling if flag set
pop bx ; else go schedule
pop ds
jmp scheduler
;
no_sched:
mov ds,_dgroup
mov _tsk_pretick,1 ; Mark preemption pending
pop bx
pop ds
iret
;
_sched_int endp
;
;
; void far asm_schedule (void)
;
; Entry for calling the scheduler. Rearranges the stack to
; contain flags.
; NOTE: Uses ax,bx.
;
_asm_schedule proc far
;
pop ax
pop bx
pushf
push bx
push ax
cli
jmp scheduler
;
_asm_schedule endp
;
;
; void far asm_c_schedule (void)
;
; Entry for conditionally calling the scheduler. Rearranges
; the stack to contain flags, then jumps to _sched_int.
; NOTE: Uses ax,bx.
;
_asm_c_schedule proc far
;
pop ax
pop bx
pushf
push bx
push ax
cli
jmp _sched_int
;
_asm_c_schedule endp
;
; word tsk_flags (void)
;
; Returns current contents of Flag register.
;
_tsk_flags proc far
pushf
pop ax
ret
_tsk_flags endp
;
;
; int tsk_dis_int (void)
;
; Returns current state of the interrupt flag (1 if ints were
; enabled), then disables interrupts.
;
_tsk_dis_int proc far
;
pushf
pop ax
mov cl,9
shr ax,cl
and ax,1
cli
ret
;
_tsk_dis_int endp
;
;
; void far tsk_ena_int (int state)
;
; Enables interrupts if 'state' is nonzero.
;
_tsk_ena_int proc far
;
push bp
mov bp,sp
mov ax,6[bp]
pop bp
or ax,ax
jz teiend
sti
teiend:
ret
;
_tsk_ena_int endp
;
; void tsk_nop (void)
;
; Do nothing. Used for very short delays.
;
_tsk_nop proc far
;
jmp short tnop1
tnop1:
jmp short tnop2
tnop2:
ret
;
_tsk_nop endp
;
end